home *** CD-ROM | disk | FTP | other *** search
/ Gold Medal Software 3 / Gold Medal Software - Volume 3 (Gold Medal) (1994).iso / graphics / 3dvect30.arj / 3D.DOC next >
Text File  |  1993-11-18  |  24KB  |  407 lines

  1.  
  2.     "Knowledge is Power, Power is Money"
  3.  
  4.     3d Vectors Source
  5.  
  6.      by John McCarthy (with a little help from his mommy:eg food)
  7.         1316 Redwood Lane
  8.         Pickering, Ontario, Canada
  9.         L1X 1C5
  10.  
  11.        (905) 831-1944 (voice, always willing to talk, but do not call at 2am)
  12.  
  13.     Documentation is in  no  defined  order. Sorry, I just  sorta  lumped  my
  14.     ideas together and ended up with this file.
  15.  
  16.     Routines support any  x mode, - but  page  flipping  is  not  allowed  in
  17.     resolutons which allow only 1 page - see "pages" constant.
  18.  
  19.     Full clipping is  performed  to  user  defind  areas - see  constants  in
  20.     equ.inc. They have   been   changed  to  memory  locations  for  variable
  21.     windowing or multiple screens.  For  windowing,  the last z locations for
  22.     that window must be remembered along with a slew of other  locations, see
  23.     vars.inc for that  info.  To change a window, save the lastz information,
  24.     reset with old lastz information and  then  call  set_clip  to change the
  25.     border clipping and screen center data.
  26.  
  27.     The theoretical screen  is  considered  to be (x,y) with  0,0  being  the
  28.     center of the  screen!.   So  -100,-100  is  somewhere  on  the top left!
  29.     actual screen goes from (0,0) to (320,200)  -  or  whatever mode size you
  30.     select.  Matt Pritchard's routines (xmode.asm) assume  0,0  to be the top
  31.     left of the  screen  while  my routines (me = John = 3d.asm) consider the
  32.     screen center to be the constants xcenter and ycenter.
  33.  
  34.     Visible space is  -4628196  to +4628196  on  all  axis  (approx).  Object
  35.     locations are 32 bit, vector routines are 16 bit, objects must be smaller
  36.     than 16 bit but are visable within about a 32 bit range.   (4 million, as
  37.     it is now,  is  very  very  far).   Since the camera is always at (0,0,0)
  38.     (relative), objects with (relative) negative z values are not seen.  This
  39.     cuts the z space to 0 to 4mil.  Visible space is always divided by 256 so
  40.     decimals can be allowed in adding, and  moving of objects.  Visible space
  41.     therefore, is actually  from -1.024 billion to +1.024  billion  with  the
  42.     lower byte having  no effect on the location.  Non-visible space is where
  43.     objects can be but won't appear on screen.   This space is a 256 *256*256
  44.     cube.  To racap:  you have 32 bit x,y,z axis with a visual  range  of  28
  45.     bits, where the  lower  8  bits don't affect the location.  (Lower 8 bits
  46.     don't count because locations are shr'ed)   i  say that the visable space
  47.     is "about" 4mil only because of the code in the make3d routine: this code
  48.     multiplies by a  constant  and then performs divide by  z  distance.   We
  49.     cannot allow the  multiply  to  overflow  and  therfore must truncate our
  50.     maximum distance to prevent this.  The  constants  for multiplication are
  51.     the screen ratio constants and the calculation to test for an overflow is
  52.     as such -2^32/2/256/(largest constant).  The constant I  have used is 464
  53.     for the y  ratio.   I  have  used  this  because  of my desire to use the
  54.     320x400 mode resolution.  Therfore, 4.3gig/2/256/464  = about 4 million -
  55.     our maximum visual  distance.  Like, trust me, you don't  really  need  a
  56.     larger universe.  Fixing  the  make  3d  routine  wont  allow  you to see
  57.     farther because then you would have to fix the rotate routine, etc, etc.
  58.  
  59.      When defining a location: ebx = x, ecx = y, ebp = z
  60.      When defining a rotation: x = pitch, y = heading, z = yaw
  61.      si refers to object number, di refers to time.
  62.  
  63.      Rotations occure in order:
  64.      zobject,xobject,yobject,ycamera,xcamera,zcamera - rotations are
  65.      compounded in matrix for faster computation.
  66.  
  67.      Vmatrix is the matrix for object rotation.  Ematrix is  the  matrix  for
  68.      camera rotation.   If  you want know where a point in space will show up
  69.      on the screen, load ebx, ecx, ebp with your x,y,z point, subtract camera
  70.      location and  call erotate (eye rotate).   The  point  will  be  rotated
  71.      according to current camera angles.  Make sure that a call to setsincose
  72.      has taken place to set the eye rotation matrix (ematrix).
  73.  
  74.      Polygon can handle any number of sides.  To draw a triangle,  make  last
  75.      point equal  to first point, eg 1,4,5,1. Number of sides of a polygon is
  76.      determined so that the polygon is  not  finished  until  the  last  side
  77.      equals the first side:  eg 1,7,6,14,13,4,2,1 would be a 7 sided polygon.
  78.      The constant maxsurfaces determines the  maximum number  of  surfaces an
  79.      object can have.  The constant maxpolys determines the maximum number of
  80.      connections a surface can have.
  81.  
  82.      Sample shape data:
  83.  
  84.      thing  dw 6        ; number of points
  85.             dw 4        ; number of surfaces
  86.             dw 25 dup (?) ; future use
  87.  
  88.             dw x,y,z    ; point 0
  89.             dw x,y,z    ; point 1
  90.             dw x,y,z
  91.             ...
  92.  
  93.             dw command
  94.             dw texture for side 1
  95.             dw texture for side 2
  96.             dw colour for side 1
  97.             dw colour for side 2
  98.             dw connection data eg (1,2,3,4,1)
  99.             dw [?,?,?] [optional surface normal if command 128 used]
  100.             dw more connection data...
  101.             ...
  102.  
  103.     There are several  commands  one can use for each surface.  Commands like
  104.     steel texture, always visible, opposite  colours,  etc.  View the objects
  105.     include file to see what/how to use them.
  106.  
  107.     Bitmaps can be part of an object or be made as seperate  objects.  I will
  108.     be using the  bitmaps  for  things  like  explosions, smoke (from damaged
  109.     planes/spaceships) and distant suns/solar system (U know, like in x-wing)
  110.     set the values bitx and bity to the  scaling  to  be used for each bitmap
  111.     and set userotate  to  2  as  this  is the command to define  a  bitmaped
  112.     object.  vxs and  vys  are  the  additional  scaling  used for individual
  113.     objects (vxs+bitx = final scaling factor).  When part of and object, use
  114.     dw himap/lomap, point #, x scale, y scale.  Remember, scaling is added to
  115.     bitx and bity so objects have a base scale plus some individual scale.
  116.  
  117.     Complex objects don't cut it for speed!  keep your objects simple and you
  118.     can have more of them on screen at once!  maximum speed is found with low
  119.     resolutions.  High resolutions with clipped borders also provide adaquate
  120.     speed.  A shallow but wide screen (small y, big x) provides  better usage
  121.     of cpu time  than  a  tall  and thin screen.  One big object is faster to
  122.     compute than many small objects (if  same  surface area) an object viewed
  123.     from the  side  takes signifiganly less time to compute  than  if  viewed
  124.     from the top  due  to  the shallow y, large x idea. Small option has been
  125.     added for objects farther than smalldist  distance.   Object  shapes have
  126.     abcd prefixes.  Therefore,  as  object  gets  farther from  camera,  less
  127.     points/surface must be calculated.  You must define four shapes for every
  128.     shape.  Hi-res shape is a, and lo-res shape is d.
  129.        eg dd offset athing,offset bthing, offset cthing, offset dthing
  130.  
  131.     Surface data must be entered counter clockwize so side  will be  visible.
  132.     Clockwize surfaces are  visible  from  other side and will not be plotted
  133.     (unless you use a surface command override, see objects.inc)
  134.  
  135.     An increase in screen objects increases  cpu time.  However, if you  know
  136.     that you will always have the screen filled (in the case  of  floors, and
  137.     runways.) You can  disable  the clear_fill routine during those parts! if
  138.     the screen will be covered with background  walls  and  such, there is no
  139.     purpose to call  the  clear  routine to compute the next  part!   i  have
  140.     therefore added a  flag  for  the  clear_fill  routine  to use: when your
  141.     animation comes to the part when your looking at the ground or walls (and
  142.     there are NO empty spaces) toggle the  flag  to  skip  clear_fill and get
  143.     more  cpu  time.   This also works if you are approaching  an  object  or
  144.     large surface, since  the  new object will totaly cover the previous one.
  145.     Another time trick is to have your main background object include the sky
  146.     (or area to be cleared) as part of the  object.  If you are going to have
  147.     walls that go  halfway  up  the  screen,  have them go halfway  with  the
  148.     regular walls and then make another surface that goes to the top  of  the
  149.     screen (or above  if you want to move around) with the colour 0.  You can
  150.     then deactivate the  clear_fill routine  and  still  have  the  animation
  151.     appear as if the walls are completely seperate objects.
  152.  
  153.     Sorting routine for objects (as opposed to sides) uses  last  z  value to
  154.     re-sort for the  next  plot.   If you plan on drawing static pictures you
  155.     may want to call makobjs twice to: 1)  draw  and find zeds, sort, then 2)
  156.     re-draw. This will be the only way (and easiest way) to  plot an accurate
  157.     picture of what   we   have.  Don't  worry  about  calling  twice  during
  158.     animations as the first picture will  be  the  only  picture  that is not
  159.     sorted.  During animations,  all  objects are sorted properly,  based  on
  160.     previous z.
  161.  
  162.     Routines which are  expected to be used in animations have been optimized
  163.     but routines intended for use as background  and  title draw routines are
  164.     not intended to be fast.
  165.  
  166.      PLEASE DOCUMENT YOUR CHANGES!!
  167.  
  168.     Newfollow routine does  not  handle  object  lock on well  if  object  is
  169.     accelerating.  The routine  calculates  where  the  object  will be in di
  170.     frames and attempts to point the camera  to it in di frames.  However, if
  171.     the object is  accelerating, then the object will not  be  where  it  was
  172.     expected to be  at  that  time.   So  the  camera  must re-lock on to its
  173.     target.  This loop commences until the  camera  actually has locked on to
  174.     the target object, from this point on, the camera will  follow the object
  175.     regardless of motion.   The  re-lock on sequence takes the last number of
  176.     frames and divides it by two, so the re-lock on loop will move toward  an
  177.     accelerating object at an accelerating rate.
  178.  
  179.     General overview: locations are 32  bit  -2.1Gig  to  +2.1Gig, angles are
  180.     16bit from 0-65535 degrees, 4 quadrants - 4096 entries each quadrant.
  181.  
  182.     Variables in vector routine are 16bit.  cosine and sine  list  are  words
  183.     but get converted into doublewords when used.
  184.  
  185.      Some public routines: (not all, just some)
  186.  
  187.   arctan           +/*% arctan(rise/run)=arctan(cx/ax).  any quadrant, 16bit
  188.   calc_angles      +/*% calculate xy angles between object di and object si
  189.   calc_middle      +/*% calculate xy angles between object di and ebx,ecx,ebp
  190.   checkfront       +/*% test points (di,bp) (si,qds) (dx,qes) for clockwize
  191.   clear_fill       +/   clears write page using xupdate and yupdate variables
  192.   compound         + *% compounds  angles  of eye and angles of object into
  193.                         matrix
  194.   cosine           +/*% eax=cos(eax), 16bit input, 32bit output
  195.   drawvect         +    draw list of vectors using points, sides and order
  196.   erotate          +/*% rotate for angles of eye, 32bit, uses ematrix
  197.   fakedraw         +/   draw line in firstbyte  and  lastbyte tables from xy1
  198.                         to xy2
  199.   flip_page        +/   flip between pages 0 and 1, wait for vertical sync
  200.   get_displacement +/*% calculate difference between objects
  201.   initfont        #     initialize font pointers
  202.   initpages       #     initialize x-mode pages for flip_page to page 0
  203.   loadpoints       + *% load points into array, rotate and translate as we go
  204.   loadsurfs        + *  load surfaces, check if visible as we go
  205.   look_at_it       +/*  immediatly  force  eyeax, eyeay to  look  at  object
  206.                         wherelook
  207.   make1obj         + *  make object si
  208.   make3d           +/*% make bx,cx,bp into bx,cx 2d pair, 16bit
  209.   makeobjs         +    make all objects then sorts based on last z location
  210.   move_to         # /*  move object si to bx,cx,bp - time di frames
  211.   newfollow       # /*  forces camera to follow object si, time to get there
  212.                         di
  213.   poly_fill        +/   uses oney,firstbyte and lastbyte to draw one surface
  214.   point_it         +/*  point object si at object di
  215.   point_dir        +/*  point object si in direction it is moving
  216.   point_to         +/*  point object si at location ebx,ecx,ebp
  217.   set_speed        +/*  calculate velocity based on angles
  218.   point_time       +/*  point obj di to bx,cx,bp in di frames
  219.   put_object       +/*  put object esi at location ebx,ecx,ebp
  220.   re_sort          +    sorts objects based on "finalzed" values
  221.   rotate           +/*% rotate bx,cx,bp (x,y,z) through matrix vrotate, 16bit
  222.   set_finall       +/*  calculate xsfinal for object (location)
  223.   set_finala       +/*  calculate vxsfinal for object (angles)
  224.   setmakeorder    #     resets order for makeobjs - for initialization
  225.   setsincose       +/   set sin and cos multipliers for eye rotations
  226.   setupbase       #     set up object base pointers to shapes
  227.   set_object_on     /*  turn object si on
  228.   set_object_off    /*  opposite
  229.   sine             +/*% ax=sin(ax), 16bit input, 32bit output
  230.   show_stars       +/   display stars in background
  231.   sort_list        +    sorts list of sides of polygon
  232.   twist_si         +/*  set angular velocity based on ebx,ecx,ebp and di(time)
  233.   updvectors       +/   updates vector xyz's and angles
  234.   where_si         +/*% return location of where object will be in di frames
  235.  
  236.      Legend:
  237.  
  238.        # used for initialization of code or new scene
  239.        + used regularly in animation loop
  240.        / can be used by user outside of animation loop if needed
  241.        * routine requires parameters passed in registers
  242.        % routine exits with results in registers
  243.        > routine wipes harddrive
  244.  
  245.     There are more routines at the end of  3d.asm  for more general functions
  246.     like find the camera displacement and finding rotational  offsets between
  247.     two objects.  U figure them out - fairly self explanatory. Also check out
  248.     poly.inc for more 3d functions and math.inc for general math functions.
  249.  
  250.     Divide overflows are  generally  caused  by  having  an object behind the
  251.     screen (or too close) and trying to calculate where  it is on the screen.
  252.     obviously this cannot  be calculated (since is it off  the  screen)  when
  253.     this happens, ztruncate  takes  over  in make3d routine.  minz is set  to
  254.     more than the maximum distance any  point  on  an  object can be from its
  255.     center of gravity.  use ztruncate to truncate underflow  of  z  to higher
  256.     values to prevent  overflows  due  to  the  object being too wide for the
  257.     camera.  increasing the zmin value prevents objects from coming too close
  258.     to the screen.   however,  large  objects  (like battlecruisers,  landing
  259.     strips) must be  allowed  to  come  close,  as  the  camera pans over the
  260.     object, in this case, zmin is low but  ztruncate takes over to "warp" the
  261.     object to an  appropiate on screen location.  ztruncate  used  in  make3d
  262.     routine does not  provide  a  true  rendition of what a very-close object
  263.     would look like but it's fast and simple.  Generally, these values do not
  264.     need to be changed unless close objects  appear flat or objects disappear
  265.     when they become  too close.  Objects disappear when  they  move  to  the
  266.     other side of the camera.
  267.  
  268.     Drawvect  routine has a seperate routine for drawing lines (as opposed to
  269.     surfaces).  The fake_line  routine and poly_fill routine could do the job
  270.     but they were too slow.  The line was drawn twice then filled just like a
  271.     polygon but now a seperate routine clipps  and  draws.  If you  need/want
  272.     to use this line  drawing  routine  it  has   been   seperated  from  the
  273.     draw_vect  routine.  I  do  not use the xmode line draw by Matt Pritchard
  274.     as it does not allow for clipping.
  275.  
  276.     Sin and cosin tables - 90 degrees is now 16384, 180=32768...
  277.  
  278.     Move_si routine - to move an object around, load up ebx, ecx and ebp with
  279.     the x,y,z locations of where you want the object to end up.  Load di with
  280.     the time you would like the object to take to get there. Load si with the
  281.     object number you want to move and call  move_si.  The updvectors routine
  282.     does the rest!
  283.  
  284.     To look at an object.  either 1) put the object number  in  wherelook. or
  285.     2) load si  with the object to look at, load di with the time to move the
  286.     camera to the object, and call new_follow.
  287.  
  288.     Just think, only  7 months ago (march '93), i had trouble  programming  a
  289.     batch file!
  290.  
  291.   Shape data can be almost as large as you need it 'till it crashes. try a cube
  292.   20000x20000x20000.    calculations  use  32  bit  registers  and  can  handle
  293.   up to 16 bit locations.  keeping the object size small will  allow  a  larger
  294.   visible space.  but larger objects will allow you to  get  closer  with  more
  295.   accuracy in the mathematics of rotations.
  296.  
  297.   List of command bits to date: (for object definitions)
  298.  
  299.   note: "visible" = "points appear counter-clockwise"
  300.  
  301.   texture definitions:
  302.  
  303.     0       - normal surface, no features, constant colour.
  304.     wavey   - steel texture for surface 0 = none,  colour  offset  determines
  305.               screen offset for texture.  eg 16+7 will use colour block 16-31
  306.               but make the sine wave texture 14 (7*2) lines down. this is  so
  307.               all sine wave textures do not appear on the same line.
  308.               windows and engines look good with this feature.
  309.     shade   - lambert shading bit, must have normal calculated or  at  least
  310.               have    free    space     for    pre_cal_lambert    to    use:
  311.               eg 128,16*1,1,2,3,1, ?,?,?<- these 3 words are surface normal!
  312.     inverse - inversion bit for shading option.  0=normal shading, 1=inverse
  313.               if option +4  is used, inversion  automatically  occures  when
  314.               other side is displayed.
  315.     glow    - =shade+inverse
  316.     last    - colour has same colour as previous surface (used when
  317.               you want gourad shading, but want to avoid  duplicate
  318.               calculations - don't set gourad bit if this  is  what
  319.               you use it for.) when this is used, the colour number
  320.               determines the new colour block to use.  the  shading
  321.               of this colour will be the same as the surface before
  322.               it, but the colour block can be different.
  323.  
  324.   commands:
  325.  
  326.     point   - defines a single point; must be repeated! eg dw 64,col,3,3
  327.     line    - if used, defines a line (must be set to define a true line)
  328.     himap   - if set, defines a bitmap,eg: point #, bitmap #, x scale,y scale
  329.     lomap   - uses 1/4 scaled bitmap (every 4'th pixel is sampled), fast
  330.  
  331.     iterate - generate iteration if side visible (iteration = sub-object)
  332.  
  333.     both    - side is always visible no matter angle, skips counter-clowise test
  334.             - "both sides have same texture"
  335.     double  - side is always visible but other side has high byte colour
  336.               "double sided surface"
  337.               note: if this is used, option "both" must not be used!!
  338.     onscr   - test if side is on screen - don't use if all points are
  339.               outside clipping parameters.
  340.     check   - dont plot this side, just use as test points for visibility.
  341.               this is mostly used with iterations.
  342.  
  343.   There are two kinds of bitmaps and points.  Those which  are  inside  objects
  344.   and those which are seperate objects themselves. if userotate object  command
  345.   is set to himap/point,then  the  entire  object  is  considered  as  a  point
  346.   or bitmap.  But if userotate is not set this way, then  a  normal  object  is
  347.   drawn and bitmaps then come from within the object definitions (below).  this
  348.   way, bitmaps and points can be either part of a larger object,  or  they  are
  349.   computed fast on their own. (eg explosions and bullets as  seperate  objects)
  350.  
  351.   Note: When writing surface descriptions, try to make the  first value unique
  352.   from any other first value.  this way, the sort routine  will  give  a  more
  353.   accurate sorting of sides. eg 1,3,6,1  2,4,1,2  rather than 1,3,6,1  1,2,4,1
  354.  
  355.   to recap:
  356.  
  357.          0 = constant colour, only visible from counter-clockwise side
  358.      wavey = sine texture
  359.      shade = shading - requires 3 blank words for surface normal eg dw 0,0,0
  360.    inverse = invert the shading direction, 0=normal, 1=sun is other way.
  361.       last = use intensity from previous surface (not colour, only intensity)
  362.      point = point
  363.       line = line
  364.      himap = bitmap (scalable, non-rotatable)
  365.      lomap = bitmap (scalable, non-rotatable)
  366.    iterate = generate iteration if side visible
  367.       both = always visible
  368.     double = always visible but other side has high byte colour,"double sided"
  369.      onscr = plot side only if all the following points are on the screen
  370.      check = dont plot side but use the following points as a test for visiblity
  371.  
  372.   What you can't mix on a single surface: "double" with "both"!!
  373.  
  374.   You do not have to define a point for the center of the  object.  the  point
  375.   0 defines the center of the object.  this is different from earlier versions
  376.  
  377.   Remember that negative y (-y) is up, +y is down.  this is opposite  from our
  378.   regular grade 13 mathematics but it is consistant with the computers  screen
  379.   arrangement.  if your objects look funny, make sure you have this correct.
  380.  
  381.   The shading for objects requires that 3  words be  present  after  the  side
  382.   definition.  These 3 words represent the surface normal to the side and  can
  383.   be either set by you (slow and tedious) by using the normal.bas program,  or
  384.   can be set up by the routine pre_cal_lambert.  This routine scans the object
  385.   to find surfaces that have the shading bit set (128).   The  surface  normal
  386.   will be calculated for that surface and stored in the 3 words set  aside  by
  387.   you.  If you remove the shading feature from a surface, make sure you remove
  388.   the extra 3 words or it will screw up.  But you knew that right.  To use the
  389.   routine pre_cal_lambert, load si with the object you wish to scan, and call.
  390.   make sure objbase points to the offset of the object.  si will be the object
  391.   number, eg 0,1,2,3, not the offset. The offset will come from objbase.
  392.  
  393.   Each on-screen object can have it's own colour palette scheme by setting the
  394.   palxref offsets to a cross reference palette.  this uses the xlat command to
  395.   take the objects colour, and xlat it into a new colour  based  on  the  xref
  396.   table you provide.  each object can have it own xref table.  this way,  many
  397.   on-screen objects can use the same shape data while each is coloured  with a
  398.   different colour scheme (5 stuka  airplanes  all  coloured  differently, for
  399.   example)  You will find the palxref tables (for each object remember) in the
  400.   file equ.inc.  A routine set_xref_palette has been provided for you  so  you
  401.   can set the xref offset (this routine is in poly.inc)
  402.  
  403.   To have a bitmap on the screen (scalable but non-rotatable) use option himap
  404.   in either userotate or as an object command.  Lomap  uses  the  same  bitmap
  405.   method but only draws every 4'th pixel - good for explosions and smoke.
  406.  
  407.